﻿using ELTE.SEM.Common;
using ELTE.SEM.Data.Repository;
using ELTE.SEM.Data.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using ELTE.SEM.Common.Enums;

namespace ELTE.SEM.Data.Managers
{
    public class UserManager : ManagerBase
    {
        public UserManager()
            : base() { 
            Repo = new UsersRepository(this.Entities); 
            FolderRepo = new FolderRepository(this.Entities);
            ErrorLogRepo = new ErrorLogRepository(this.Entities);
        }
        public UserManager(SemDataEntities entities)
            : base(entities) { 
            Repo = new UsersRepository(entities); 
            FolderRepo = new FolderRepository(entities);
            ErrorLogRepo = new ErrorLogRepository(entities);
        }


        private UsersRepository Repo { get; set; }
        private FolderRepository FolderRepo { get; set; }
        private ErrorLogRepository ErrorLogRepo { get; set; }

        public bool Authenticate(LoginViewModel model)
        {
            return Repo.Login(model.UserName, model.Password) != null;
        }

        public UserRoleLevel GetUsersRole(string userName)
        {
            User user = Repo.GetAll().SingleOrDefault(usr => usr.Name == userName);
            if (user != null)
            {
                return user.GetUserRoleLevel();
            }
            else
            {
                return UserRoleLevel.Unknown;
            }
        }



        public String Register(RegisterViewModel model)
        {
            if (Repo.HasUser(model.Name))
            {
                return "Felhasználó név foglalt.";
            }
            else
            {
                if (Repo.RegisterUser(new User
                {
                    Name = model.Name,
                    Password = Encrypter.Encrypt(model.Password)
                }))
                {
                    return "Sikeres regisztráció";
                }
                else
                {
                    return "Regisztráció sikertelen";
                }
            }
        }

        public int GetUserId(string userName)
        {
            try
            {
               return Repo.GetUserId(userName);
            }
            catch (Exception ex)
            {
                ErrorLogRepo.AddErrorLog(MethodInfo.GetCurrentMethod().DeclaringType.Name, MethodInfo.GetCurrentMethod().Name, ex.ToString(), String.Empty);
                return 0;
            }
        }

        public List<UserViewModel> GetUsersWithRole(int pageNumber, int amountToTake)
        {
            try
            {
                return Repo
                .GetAll()
                .OrderBy(user => user.Name)
                .Skip(pageNumber * amountToTake) //az adott oldalszámnak megfelelő oldalnyit ki kell hagyni
                .Take(amountToTake)
                .ToList()
                .Select(user =>
                    new UserViewModel
                    {
                        UserId = user.Id,
                        UserName = user.Name,
                        Role = user.GetUserRoleViewModel()
                    }).ToList();

            }
            catch (Exception ex)
            {
                ErrorLogRepo.AddErrorLog(MethodInfo.GetCurrentMethod().DeclaringType.Name, MethodInfo.GetCurrentMethod().Name, ex.ToString(), String.Empty);
                return null;
            }

        }

        public UserFoldersViewModel GetUserFolderAccess(int userId, bool onlyHasAccess)
        {
            UserFoldersViewModel model = new UserFoldersViewModel { UserId = userId, FolderAccess = new List<SemFolderAccessViewModel>() };
            try
            {
                User user = Repo.GetById(userId);
                if (user != null)
                {
                    model.FolderAccess = FolderRepo.GetFolderAccesses(user.Id);
                }
                if (onlyHasAccess) {
                    model.FolderAccess = model.FolderAccess.Where(fa => fa.HasAccess).ToList();
                }
            }
            catch (Exception ex)
            {
                ErrorLogRepo.AddErrorLog(MethodInfo.GetCurrentMethod().DeclaringType.Name, MethodInfo.GetCurrentMethod().Name, ex.ToString(), String.Empty);
            }
            
            return model;
        }

        public bool SetUserFolderAccess(UserFoldersViewModel model)
        {
            bool result = true;
            try
            {
                //minden egyes elemre kell
                model.FolderAccess.ForEach(folderAccess =>
                    FolderRepo.SetFolderAccess(folderAccess.Folder.Id, model.UserId, folderAccess.HasAccess)
                    );
                FolderRepo.Save();
            }
            catch (Exception ex)
            {
                ErrorLogRepo.AddErrorLog(MethodInfo.GetCurrentMethod().DeclaringType.Name, MethodInfo.GetCurrentMethod().Name, ex.ToString(), String.Empty);
                result = false;
            }
            return result;
        }

        public bool HasAccess(string userName, int folderId)
        {
            return FolderRepo.IsAccessibleFor(userName, folderId);
        }

        public bool ChangeName(string fromUserName, string toUserName)
        {
            bool result = true;
            try
            {
                User user = Repo.GetAll().SingleOrDefault(usr => usr.Name == fromUserName);
                if (user != null)
                {
                    if (!Repo.GetAll().Any(usr => usr.Name == toUserName))
                    {
                        user.Name = toUserName;
                        Repo.Save();
                    }
                    else
                    {
                        result = false;
                    }
                }
                else
                {
                    result = false;
                }
            }
            catch (Exception ex)
            {
                ErrorLogRepo.AddErrorLog(MethodInfo.GetCurrentMethod().DeclaringType.Name, MethodInfo.GetCurrentMethod().Name, ex.ToString(), String.Empty);
            }
            return result;
        }

        public bool ChangeRole(string userName, int roleId)
        {
            bool result = true;
            try
            {
                User user = Repo.GetAll().SingleOrDefault(usr => usr.Name == userName);
                if (user != null)
                {
                    if (user.UsersInRoles.Count > 0)
                    {
                        //már van szerep beállítva
                        UserRole roleById = Repo.GetRoleById(roleId);
                        if (roleById != null)
                        {
                            UsersInRole firstRole = user.UsersInRoles.First();
                            firstRole.UserRoleId = roleById.Id;
                            Repo.Save();
                        }
                        else
                        {
                            //TODO: log error
                            result = false;
                        }
                    }
                    else
                    {
                        UserRole roleById = Repo.GetRoleById(roleId);
                        if (roleById != null)
                        {
                            user.UsersInRoles.Add(new UsersInRole { UserId = user.Id, Created = DateTime.Now, UserRoleId = roleById.Id });
                            Repo.Save();
                        }
                        else
                        {
                            //TODO: log error
                            result = false;
                        }
                    }
                }
                else
                {
                    result = false;
                }
            }
            catch (Exception ex)
            {
                ErrorLogRepo.AddErrorLog(MethodInfo.GetCurrentMethod().DeclaringType.Name, MethodInfo.GetCurrentMethod().Name, ex.ToString(), String.Empty);
            }
            return result;
        }

        public List<KeyValuePair<int, string>> GetAvailableUserRoles()
        {
            List<KeyValuePair<int, string>> availableRoles = new List<KeyValuePair<int,string>>();
            try
            {
                Repo.GetAvailableUserRoles().ForEach(userRole => availableRoles.Add(new KeyValuePair<int, string>(userRole.Id, userRole.RoleDisplayName)));
            }
            catch (Exception ex)
            {
                ErrorLogRepo.AddErrorLog(MethodInfo.GetCurrentMethod().DeclaringType.Name, MethodInfo.GetCurrentMethod().Name, ex.ToString(), String.Empty);
            }
            return availableRoles;
        }
    }
}
